﻿using Growatt.OutPutDataProcess;
using Sunny.UI;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Vosc.VirtualOscilloscope;


namespace Growatt.WaveData.DataSetResolve
{
    public class DwarfHelper
    {
        public DwarfHelper()
        {
        }
        List<Die> allDies = null;
        List<Die> DW_TAG_variable = null;
        // 私有的静态实例字段
        private static DwarfHelper _dwarfHelperInstance;
        // 公共的静态属性，用于获取实例
        public static DwarfHelper DwarfHelperInstance
        {
            get
            {
                if (_dwarfHelperInstance == null)
                {
                    _dwarfHelperInstance = new DwarfHelper();
                }
                return _dwarfHelperInstance;
            }
        }
        Die getDieFromvariableName(string variableName)
        {

            Die die1 = new Die();
            var singleName = variableName.Split('[')[0];

            var first_DW_AT_Name = string.Empty;
            var die = DW_TAG_variable.First(die_item =>
            {
                var attribute_item = die_item.Attributes.First(o => o.Type.Equals("DW_AT_name"));
                return attribute_item.Value.StringValue.Equals(singleName);
            });

            return die;
        }
        Die getDieChildren(Die dieParent, string ChildrenName)
        {
            var name = ChildrenName.Split('[')[0];
            var dieChildren = dieParent.Dies.FirstOrDefault(die_item =>
            {
                var attribute_item_Dies = die_item.Attributes.First(o => o.Type.Equals("DW_AT_name"));
                return attribute_item_Dies.Value.StringValue.Equals(name);
            });

            return dieChildren;
        }
        List<int> ExtractNumbers(string input)
        {
            List<int> numbers = new List<int>();
            // 正则表达式模式匹配字符串中的数字
            // 正则表达式匹配方括号中的数字
            MatchCollection matches = Regex.Matches(input, @"\[([^\]]+)\]");

            foreach (Match match in matches)
            {
                if (match.Success && match.Groups[1].Success)
                {
                    // 将匹配到的数字字符串转换为整数并添加到列表中
                    numbers.Add(int.Parse(match.Groups[1].Value));
                }
            }

            return numbers;
        }
        List<Die> GetAllDies(DwarfInfo section)
        {
            List<Die> result = new List<Die>();

            foreach (var compileUnit in section.iter_CUs)
            {
                if (compileUnit.TopLevelDie != null)
                {
                    result.AddRange(GetAllDiesRecursively(compileUnit.TopLevelDie));
                }
            }

            return result;
        }
        static int[] ExtractIndices(string input)
        {
            // 使用正则表达式提取索引
            string pattern = @"\[(\d+)\]";
            MatchCollection matches = Regex.Matches(input, pattern);

            foreach (Match match in matches)
            {
                string index = match.Groups[1].Value;
            }
            // 将提取的字符串形式的索引转换为整数
            int[] indices = new int[matches.Count];
            for (int i = 0; i < matches.Count; i++)
            {
                indices[i] = int.Parse(matches[i].Groups[1].Value);
            }

            return indices;
        }
        static int CalculateAddressColumnMajor(int baseAddress, int[] dimensions, int elementSize, int[] indices)
        {
            int offset = 0;
            int multiplier = 1;

            // 从最内层维度开始计算偏移量
            for (int i = indices.Length - 1; i >= 0; i--)
            {
                offset += indices[i] * multiplier;
                multiplier *= dimensions[i];
            }

            // 计算最终地址
            return baseAddress + offset * elementSize;
        }





        (int, Die) calculateOffset(string variableNameSegCurrentName, Die dieCurrent)
        {
            //进来的将会是成员
            var SizeOffset = "0";
            var offset_member = "0";
            var arraySzie = variableNameSegCurrentName.Where(o => o.Equals(']')).Count();
            var singleName = variableNameSegCurrentName.Split('[')[0];
            var DW_AT_data_member_location = dieCurrent.Attributes.FirstOrDefault(o => o.Type.Equals("DW_AT_data_member_location"));
            if (DW_AT_data_member_location != null)
            {
                offset_member = DW_AT_data_member_location.Value.BlockValue;
                offset_member = offset_member.Split(' ')[1].Replace("0x", "");
            }
            var item = getFinalDieSize(dieCurrent, variableNameSegCurrentName);
            SizeOffset = item.Item1.ToString();
            dieCurrent = item.Item2;
            Debug.WriteLine($"{variableNameSegCurrentName}偏移:{offset_member}" + $"   {variableNameSegCurrentName}  Size:{SizeOffset}");
            return (int.Parse(SizeOffset) + Convert.ToInt32(offset_member, 16), dieCurrent);
        }
        public static string CurrentDW_AT_byte_size = string.Empty;

        (string, Die) getFinalDieSize(Die OriginalDie, string singleName)
        {
            String Sec = string.Empty;
            int NeedSize = 0;
            if (singleName.Contains("["))
            {
                Sec = singleName.Split('[')[1];
                NeedSize = 1;
                var dataRef = OriginalDie.Attributes.FirstOrDefault(o => o.Type == "DW_AT_type");
                if (dataRef != null)
                {
                    var ad = dataRef.Value.RefValue.Idref;
                    var data = allDies.FirstOrDefault(die => die.ID == ad);
                    List<int> strings = new List<int>();
                    if (data != null)
                    {
                        for (int i = 0; i < data.Dies.Count; i++)
                        {
                            var ab = data.Dies[i].Attributes.FirstOrDefault(o => o.Type.Equals("DW_AT_upper_bound"));
                            if (ab != null)
                            {
                                strings.Add((Convert.ToInt32(ab.Value.ConstValue.Replace("0x", ""), 16) + 1));
                            }
                        }
                        string input = singleName; // 输入的字符串
                        int baseAddress = 0; // 假设的数组起始地址
                        int[] dimensions = strings.ToArray(); // 数组的维度
                        OriginalDie = GetFinalDie(OriginalDie);
                        var size1 = OriginalDie.Attributes.First(o => o.Type.Equals("DW_AT_byte_size")).Value.ConstValue;
                        if (OriginalDie.Tag.Equals("DW_TAG_base_type")) //如果是基础类型的时候才需要显示类型信息
                        {
                            var StringValue = OriginalDie.Attributes.First(o => o.Type.Equals("DW_AT_name")).Value.StringValue;
                            if (StringValue != null) //获取当前的DW_TAG_base_type
                                DW_TAG_base_type = StringValue;
                        }
                        int elementSize = Convert.ToInt32(size1.Replace("0x", ""), 16); // 每个元素的大小
                        // 提取索引
                        int[] indices = ExtractIndices(input);
                        // 计算地址
                        var address = CalculateAddressColumnMajor(baseAddress, dimensions, elementSize, indices).ToString();
                        return (address.Replace("0x", ""), OriginalDie);
                    }
                }
            }
            var sizeNoArr = "0";
            OriginalDie = GetFinalDie(OriginalDie);
            if (OriginalDie.Tag.Equals("DW_TAG_base_type"))//如果是基础类型的时候才需要显示类型信息
            {
                var StringValueNoArrary = OriginalDie.Attributes.First(o => o.Type.Equals("DW_AT_name")).Value.StringValue;
                if (StringValueNoArrary != null) //获取当前的DW_TAG_base_type
                    DW_TAG_base_type = StringValueNoArrary;
            }
            return (sizeNoArr.Replace("0x", ""), OriginalDie);
        }
        Die GetFinalDie(Die originalDie)
        {
            var currentDie = originalDie;

            while (currentDie != null)
            {
                var typeAttribute = currentDie.Attributes.FirstOrDefault(o => o.Type.Equals("DW_AT_type"));

                if (typeAttribute == null)
                {
                    return currentDie;
                }

                var dieID = typeAttribute.Value.RefValue.Idref;
                currentDie = allDies.FirstOrDefault(die => die.ID == dieID);
            }

            return null; // 如果没有找到最终的Die，返回null
        }
        List<Die> GetAllDiesRecursively(Die die)
        {
            List<Die> result = new List<Die> { die };

            foreach (var childDie in die.Dies)
            {
                result.AddRange(GetAllDiesRecursively(childDie));
            }

            return result;
        }
        SymbolTableSection compileUnit_SymbolTable = null;

        public void LoadFile(string outFileName = "outModual.bat")
        {
            // 定义要执行的命令
            #region 生成appoutSample文件
            string StringFilename = "appoutSampleTest";
            if (!File.Exists(outFileName))
            {
                UIMessageBox.Show("文件不存在");
                return;
            }
            var tartInfo_FileName = Path.Combine(Environment.CurrentDirectory, "Parser");
            string cmd = $"-xg --dwarf_display=dinfo {outFileName}";
            //// 创建一个新的进程
            Process process = new Process();
            process.StartInfo.FileName = Path.Combine(Environment.CurrentDirectory, "Parser", "ofd6x.exe"); // 使用ofd6x.exe
            process.StartInfo.Arguments = cmd; // 设置命令参数
            process.StartInfo.UseShellExecute = false; // 不使用操作系统外壳来启动
            process.StartInfo.RedirectStandardOutput = true; // 重定向标准输出
            process.StartInfo.RedirectStandardError = true; // 重定向标准错误
            process.StartInfo.CreateNoWindow = true; // 不创建窗口
            process.StartInfo.WorkingDirectory = Path.Combine(Environment.CurrentDirectory, "Parser"); // 设置工作目录
            try
            {
                // 启动进程
                process.Start();

                // 读取输出
                string output = process.StandardOutput.ReadToEnd();
                File.WriteAllText(Path.Combine(tartInfo_FileName, StringFilename) + ".txt", output);
                process.WaitForExit();
            }
            catch (Exception ex)
            {
                Console.WriteLine("An error occurred:");
                Console.WriteLine(ex.Message);
            }
            finally
            {
                // 确保释放资源
                process.Dispose();
            }
            #endregion
            string xml = string.Empty;
            string xml2 = string.Empty;
            string xml3 = string.Empty;


            string filePath = Path.Combine(Environment.CurrentDirectory, "Parser", $"{StringFilename}.txt"); // 替换为你的文件路径
            List<StringBuilder> StringBuilder = null;
            List<StringBuilder> StringBuilder2 = null;
            List<StringBuilder> StringBuilder3 = null;

            try
            {
                #region MyRegion
                int count = 0;
                using (StreamReader reader = new StreamReader(filePath))
                {
                    string line;

                    while ((line = reader.ReadLine()) != null)
                    {

                        if (line.Contains("<die id=") && StringBuilder?.Count == 1)
                        {
                            count++;
                        }
                        if (line.Contains("<symbol_table>"))
                        {
                            StringBuilder2 = new List<StringBuilder>();
                        }
                        if (line.Contains("<string_table>"))
                        {
                            StringBuilder3 = new List<StringBuilder>();
                        }
                        if (line.Contains("<dwarf>"))
                        {
                            StringBuilder = new List<StringBuilder>();
                        }

                        if (line.Contains("<section>") && StringBuilder?.Count == 0)
                        {
                            StringBuilder.Add(new System.Text.StringBuilder().AppendLine(line));
                            continue;
                        }
                        if ((line.Contains("<symbol_table>") && StringBuilder2?.Count == 0))
                        {
                            StringBuilder2.Add(new System.Text.StringBuilder().AppendLine(line));
                            continue;
                        }
                        if (line.Contains("<string_table>") && StringBuilder3?.Count == 0)
                        {
                            StringBuilder3.Add(new System.Text.StringBuilder().AppendLine(line));
                            continue;
                        }
                        if (StringBuilder?.Count == 1)
                        {
                            StringBuilder[0].AppendLine(line);

                            if (line.Contains("</section>"))
                            {
                                StringBuilder.Add(new System.Text.StringBuilder());
                            }
                        }

                        if (StringBuilder2?.Count == 1)
                        {
                            StringBuilder2[0].AppendLine(line);
                            if (line.Contains("</symbol_table>"))
                            {
                                StringBuilder2.Add(new System.Text.StringBuilder());
                            }
                        }

                        if (StringBuilder3?.Count == 1)
                        {
                            StringBuilder3[0].AppendLine(line);
                            if (line.Contains("</string_table>"))
                            {
                                StringBuilder3.Add(new System.Text.StringBuilder());
                            }
                        }
                    }
                }
                #endregion
            }
            catch (Exception ex)
            {
                Console.WriteLine("An error occurred: " + ex.Message);
            }
            xml = StringBuilder[0].ToString();
            xml = RemoveInvalidXmlChars(xml);
            xml2 = StringBuilder2[0].ToString();
            xml2 = RemoveInvalidXmlChars(xml2);
            xml3 = StringBuilder3[0].ToString();
            xml3 = RemoveInvalidXmlChars(xml3);
            // 创建 XmlSerializer 实例
            XmlSerializer serializer = new XmlSerializer(typeof(DwarfInfo));
            XmlSerializer serializerSymbolTable = new XmlSerializer(typeof(SymbolTableSection));
            XmlSerializer serializerStringTable = new XmlSerializer(typeof(StringTable));
            DwarfInfo compileUnit_Section = null;
            StringTable compileUnit_StringTable = null;
            using (StringReader reader = new StringReader(xml))
            {
                compileUnit_Section = (DwarfInfo)serializer.Deserialize(reader);
            }

            string variableName = string.Empty;

            using (StringReader reader = new StringReader(xml2))
            {
                compileUnit_SymbolTable = (SymbolTableSection)serializerSymbolTable.Deserialize(reader);
            }

            using (StringReader reader = new StringReader(xml3))
            {
                compileUnit_StringTable = (StringTable)serializerStringTable.Deserialize(reader);
            }
            // 获取所有 Die 对象
            allDies = GetAllDies(compileUnit_Section);
            DW_TAG_variable = allDies.Where(o => o.Tag.Equals("DW_TAG_variable")).ToList();
        }

        public static string DW_TAG_base_type = string.Empty;

        static string RemoveInvalidXmlChars(string input)
        {
            StringBuilder cleanString = new StringBuilder();
            foreach (char c in input)
            {
                int codePoint = Convert.ToInt32(c);
                if ((codePoint == 0x9) || (codePoint == 0xA) || (codePoint == 0xD) ||
                    ((codePoint >= 0x20) && (codePoint <= 0xD7FF)) ||
                    ((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) ||
                    ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF)))
                {
                    cleanString.Append(c);
                }
            }
            return cleanString.ToString();
        }
        public void GetAddress(List<VariableInfo> variables)
        {
            if (!(allDies?.Count > 0))
                LoadFile(OscilloscopeControl.ModelAppSettingsCustom.OutPathHistory);
            StringBuilder stringBuilder = new();
            string variableName = string.Empty;
            VariableInfo variableInfo = null;
            try
            {
                for (int w = 0; w < variables.Count; w++)
                {
                    DW_TAG_base_type = string.Empty;
                    var sizeBaseParent = "0";
                    variableInfo = variables[w];
                    variableName = variableInfo.VariableName;
                    var variableNameArrary = variableName.Split('.');
                    List<string> ListSize = new List<string>();
                    var len = variableName.Split('.').Length;
                    Die dieChildren = null;
                    Die dieParent = getDieFromvariableName(variableNameArrary[0]);
                    var singleName = variableName.Split('.')[0].Split('[')[0];
                    foreach (var item in compileUnit_SymbolTable.Symbols)
                        item.Name = item.Name.Split('$')[0];
                    var DW_AT_data_member_location = compileUnit_SymbolTable.Symbols.FirstOrDefault(o => o.Name.Equals("_" + singleName));
                    var DW_AT_data_member_location1 = compileUnit_SymbolTable.Symbolself32.FirstOrDefault(o => o.st_name_string.Equals("_" + singleName));
                    if (DW_AT_data_member_location != null)
                    {
                        var offset_member = DW_AT_data_member_location.Value.Replace("0x", "");
                        ListSize.Add(offset_member);
                    }
                    if (DW_AT_data_member_location1 != null)
                    {
                        var offset_member = DW_AT_data_member_location1.Value.Replace("0x", "");
                        ListSize.Add(offset_member);
                    }
                    if (DW_AT_data_member_location == null)
                        return;
                    if (len >= 1)
                    {
                        var item = getFinalDieSize(dieParent, variableNameArrary[0]);
                        dieParent = item.Item2;
                        sizeBaseParent = item.Item1;
                        if (len > 1)
                        {
                            for (int i = 1; i < len; i++)//从第一个开始
                            {
                                var itemsSp = variableNameArrary[i];
                                dieChildren = getDieChildren(dieParent, itemsSp);
                                var tt = calculateOffset(itemsSp, dieChildren);
                                ListSize.Add(tt.Item1.ToString());
                                dieParent = tt.Item2;
                            }
                        }
                    }
                    var oofset = ListSize.Skip(1).Select(o => int.Parse(o)).Sum();
                    var f = (ulong)oofset + Convert.ToUInt64(ListSize[0].Replace("0x", ""), 16) + Convert.ToUInt64(sizeBaseParent);
                    variableInfo.Address = f.ToString("X8");
                    Debug.WriteLine("variableName:" + variableName
                        + "  address:" + string.Join(" ", ListSize) + "   Finaladdress:0x" + f.ToString("X8")
                        + "   Sum:" + oofset + "   " + $"   anticipate-Address: {variableInfo.Address}" + "当前类型:" + DW_TAG_base_type);
                    variableInfo.SzieVar = DW_TAG_base_type;
                }
            }
            catch (Exception ex)
            {
                // Debug.WriteLine(variableName);
                // Debug.WriteLine(ex);
            }
        }
    }
}